#ifndef __EASY_HOOK_LIB_H__
#define __EASY_HOOK_LIB_H__

#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <functional>

namespace EasyHook
{

// Hook管理器类 - 单例模式
class HookManager
{
public:
    static HookManager &getInstance();

    // 初始化Hook系统
    bool initialize();

    // 清理Hook系统
    bool cleanup();

    // 创建并启用Hook
    template<typename FuncType>
    bool createHook(FuncType targetFunc, FuncType detourFunc, FuncType *originalFunc = nullptr);

    // 通过函数名创建Hook（用于系统API）
    bool createAPIHook(const std::string &moduleName, const std::string &funcName, LPVOID detourFunc, LPVOID *originalFunc = nullptr);

    // 启用所有Hook
    bool enableAllHooks();

    // 禁用所有Hook
    bool disableAllHooks();

    // 获取最后的错误信息
    std::string getLastError() const;

    // ================================
    // 新增：扩展功能
    // ================================

    // 通过偏移获取地址
    LPVOID GetAddressByOffset(const std::string &moduleName, DWORD offset);

    // 通过函数名获取地址
    LPVOID GetFunctionAddress(const std::string &moduleName, const std::string &functionName);

    // 通过偏移创建Hook
    bool createOffsetHook(const std::string &moduleName, DWORD offset, LPVOID detourFunc, LPVOID *originalFunc = nullptr);

private:
    HookManager() = default;
    ~HookManager();

    // 禁止拷贝
    HookManager(const HookManager &)            = delete;
    HookManager &operator=(const HookManager &) = delete;

    bool                initialized_ = false;
    std::string         lastError_;
    std::vector<LPVOID> hooks_;

    void        setError(const std::string &error);
    std::string statusToString(int status);
};

// RAII Hook包装类
template<typename FuncType>
class Hook
{
public:
    Hook(FuncType targetFunc, FuncType detourFunc);
    Hook(const std::string &moduleName, const std::string &funcName, FuncType detourFunc);
    // 新增：通过偏移构造Hook
    Hook(const std::string &moduleName, DWORD offset, FuncType detourFunc);
    ~Hook();

    // 获取原始函数指针
    FuncType getOriginal() const
    {
        return original_;
    }

    // 检查Hook是否成功
    bool isValid() const
    {
        return enabled_;
    }

    // 调用原始函数的便捷方法
    template<typename... Args>
    auto callOriginal(Args &&...args) -> decltype(original_(std::forward<Args>(args)...))
    {
        if (original_)
        {
            return original_(std::forward<Args>(args)...);
        }
        throw std::runtime_error("Original function not available");
    }

private:
    FuncType target_;
    FuncType detour_;
    FuncType original_;
    bool     enabled_;
};

// 模板实现包含
#include "EasyHookLib.inl"

} // namespace EasyHook

// 便捷宏定义
#define DECLARE_HOOK(FuncName, RetType, ...)                                    \
    typedef RetType(WINAPI *FuncName##_t)(__VA_ARGS__);                         \
    inline std::unique_ptr<EasyHook::Hook<FuncName##_t>> &get_hook_##FuncName() \
    {                                                                           \
        static std::unique_ptr<EasyHook::Hook<FuncName##_t>> instance;          \
        return instance;                                                        \
    }                                                                           \
    inline FuncName##_t get_original_##FuncName()                               \
    {                                                                           \
        auto &hook_ptr = get_hook_##FuncName();                                 \
        return hook_ptr ? hook_ptr->getOriginal() : nullptr;                    \
    }                                                                           \
    RetType WINAPI Detour##FuncName(__VA_ARGS__)

#define IMPLEMENT_HOOK(FuncName, ModuleName, FuncNameStr)                                                           \
    inline void Install##FuncName##Hook()                                                                           \
    {                                                                                                               \
        auto &hook_ptr = get_hook_##FuncName();                                                                     \
        hook_ptr       = std::make_unique<EasyHook::Hook<FuncName##_t>>(ModuleName, FuncNameStr, Detour##FuncName); \
        if (!hook_ptr->isValid())                                                                                   \
        {                                                                                                           \
            std::cerr << "Failed to install " #FuncName " hook!" << std::endl;                                      \
        }                                                                                                           \
        else                                                                                                        \
        {                                                                                                           \
            std::cout << "Successfully installed " #FuncName " hook!" << std::endl;                                 \
        }                                                                                                           \
    }

#define IMPLEMENT_DIRECT_HOOK(FuncName, TargetAddr)                                                                                    \
    inline void Install##FuncName##Hook()                                                                                              \
    {                                                                                                                                  \
        auto &hook_ptr = get_hook_##FuncName();                                                                                        \
        hook_ptr       = std::make_unique<EasyHook::Hook<FuncName##_t>>(reinterpret_cast<FuncName##_t>(TargetAddr), Detour##FuncName); \
        if (!hook_ptr->isValid())                                                                                                      \
        {                                                                                                                              \
            std::cerr << "Failed to install " #FuncName " hook!" << std::endl;                                                         \
        }                                                                                                                              \
        else                                                                                                                           \
        {                                                                                                                              \
            std::cout << "Successfully installed " #FuncName " hook!" << std::endl;                                                    \
        }                                                                                                                              \
    }

// ================================
// 新增：偏移Hook宏
// ================================

#define IMPLEMENT_OFFSET_HOOK(FuncName, ModuleName, Offset)                                                                                       \
    inline void Install##FuncName##OffsetHook()                                                                                                   \
    {                                                                                                                                             \
        auto &hook_ptr = get_hook_##FuncName();                                                                                                   \
        hook_ptr       = std::make_unique<EasyHook::Hook<FuncName##_t>>(ModuleName, Offset, Detour##FuncName);                                    \
        if (!hook_ptr->isValid())                                                                                                                 \
        {                                                                                                                                         \
            std::cerr << "Failed to install " #FuncName " offset hook at " << ModuleName << "+0x" << std::hex << Offset << "!" << std::endl;      \
        }                                                                                                                                         \
        else                                                                                                                                      \
        {                                                                                                                                         \
            std::cout << "Successfully installed " #FuncName " offset hook at " << ModuleName << "+0x" << std::hex << Offset << "!" << std::endl; \
        }                                                                                                                                         \
    }

// 便捷的偏移Hook宏
#define HOOK_BY_OFFSET(moduleName, offset, detourFunc)                                                                                                                        \
    do                                                                                                                                                                        \
    {                                                                                                                                                                         \
        auto &mgr = EasyHook::HookManager::getInstance();                                                                                                                     \
        mgr.initialize();                                                                                                                                                     \
        LPVOID addr = mgr.GetAddressByOffset(moduleName, offset);                                                                                                             \
        if (addr)                                                                                                                                                             \
        {                                                                                                                                                                     \
            if (mgr.createOffsetHook(moduleName, offset, reinterpret_cast<LPVOID>(detourFunc)))                                                                               \
            {                                                                                                                                                                 \
                std::cout << "Successfully hooked " << moduleName << "+0x" << std::hex << (offset) << " at 0x" << reinterpret_cast<uintptr_t>(addr) << std::dec << std::endl; \
            }                                                                                                                                                                 \
            else                                                                                                                                                              \
            {                                                                                                                                                                 \
                std::cout << "Failed to hook " << moduleName << "+0x" << std::hex << (offset) << std::dec << std::endl;                                                       \
            }                                                                                                                                                                 \
        }                                                                                                                                                                     \
        else                                                                                                                                                                  \
        {                                                                                                                                                                     \
            std::cout << "Failed to get address for " << moduleName << "+0x" << std::hex << (offset) << std::dec << std::endl;                                                \
        }                                                                                                                                                                     \
    }                                                                                                                                                                         \
    while (0)

// 显示地址信息的便捷宏
#define SHOW_FUNCTION_ADDRESS(moduleName, functionName)                                                                                             \
    do                                                                                                                                              \
    {                                                                                                                                               \
        auto  &mgr  = EasyHook::HookManager::getInstance();                                                                                         \
        LPVOID addr = mgr.GetFunctionAddress(moduleName, functionName);                                                                             \
        if (addr)                                                                                                                                   \
        {                                                                                                                                           \
            std::cout << functionName << " (" << moduleName << ") -> 0x" << std::hex << reinterpret_cast<uintptr_t>(addr) << std::dec << std::endl; \
        }                                                                                                                                           \
        else                                                                                                                                        \
        {                                                                                                                                           \
            std::cout << functionName << " not found in " << moduleName << std::endl;                                                               \
        }                                                                                                                                           \
    }                                                                                                                                               \
    while (0)

#define SHOW_MODULE_BASE(moduleName)                                                                                                     \
    do                                                                                                                                   \
    {                                                                                                                                    \
        HMODULE hModule = GetModuleHandleA(moduleName);                                                                                  \
        if (hModule)                                                                                                                     \
        {                                                                                                                                \
            std::cout << moduleName << " base address: 0x" << std::hex << reinterpret_cast<uintptr_t>(hModule) << std::dec << std::endl; \
        }                                                                                                                                \
        else                                                                                                                             \
        {                                                                                                                                \
            std::cout << moduleName << " not loaded" << std::endl;                                                                       \
        }                                                                                                                                \
    }                                                                                                                                    \
    while (0)

// 获取原始函数的便捷宏
#define Original(FuncName) get_original_##FuncName()

// 简化的Hook安装宏
#define INSTALL_HOOK(FuncName)        Install##FuncName##Hook()
#define INSTALL_OFFSET_HOOK(FuncName) Install##FuncName##OffsetHook()

// Hook管理宏
#define SETUP_HOOKS()                                                                           \
    struct GlobalHookInitializer                                                                \
    {                                                                                           \
        GlobalHookInitializer()                                                                 \
        {                                                                                       \
            auto &mgr = EasyHook::HookManager::getInstance();                                   \
            if (!mgr.initialize())                                                              \
            {                                                                                   \
                std::cerr << "Hook initialization failed: " << mgr.getLastError() << std::endl; \
                return;                                                                         \
            }

#define INSTALL_HOOK_HERE(name)        INSTALL_HOOK(name);
#define INSTALL_OFFSET_HOOK_HERE(name) INSTALL_OFFSET_HOOK(name);

#define FINISH_HOOK_SETUP()                             \
    }                                                   \
    ~GlobalHookInitializer()                            \
    {                                                   \
        EasyHook::HookManager::getInstance().cleanup(); \
    }                                                   \
    }                                                   \
    g_globalHooks;

#endif // __EASY_HOOK_LIB_H__